package word_type

import (
	"sync"
	"word_identify/my_error"
	"word_identify/types"
	"word_identify/utils"
)

var KeywordMap = make(map[string]int)

var BoundaryMap = make(map[string]int)

var OperatorMap = make(map[string]int)

func InitKeywordMap() {
	KeywordMap["char"] = 101
	KeywordMap["int"] = 102
	KeywordMap["float"] = 103
	KeywordMap["break"] = 104
	KeywordMap["const"] = 105
	KeywordMap["return"] = 106
	KeywordMap["void"] = 107
	KeywordMap["continue"] = 108
	KeywordMap["do"] = 109
	KeywordMap["while"] = 110
	KeywordMap["if"] = 111
	KeywordMap["else"] = 112
	KeywordMap["for"] = 113
}

func InitBoundaryMap() {
	BoundaryMap["{"] = 301
	BoundaryMap["}"] = 302
	BoundaryMap[";"] = 303
	BoundaryMap[","] = 304
}

func InitOperatorMap() {
	OperatorMap["("] = 201
	OperatorMap[")"] = 202
	OperatorMap["["] = 203
	OperatorMap["]"] = 204
	OperatorMap["!"] = 205
	OperatorMap["*"] = 206
	OperatorMap["/"] = 207
	OperatorMap["%"] = 208
	OperatorMap["+"] = 209
	OperatorMap["-"] = 210
	OperatorMap["<"] = 211
	OperatorMap["<="] = 212
	OperatorMap[">"] = 213
	OperatorMap[">="] = 214
	OperatorMap["=="] = 215
	OperatorMap["!="] = 216
	OperatorMap["&&"] = 217
	OperatorMap["||"] = 218
	OperatorMap["="] = 219
	OperatorMap["|"] = 220
	OperatorMap["&"] = 221
	OperatorMap["++"] = 222
	OperatorMap["--"] = 223
	OperatorMap["+="] = 224
	OperatorMap["-="] = 225
	OperatorMap[">>"] = 226
	OperatorMap["<<"] = 227
}

var d1 = "<>=!"
var d2 = "&|"

func WordCategory(i int, line string, words [][]types.Word, wg *sync.WaitGroup) {
	defer (*wg).Done()
	lineLen := len(line)
	for j := 0; j < lineLen; j++ {
		if j < lineLen-1 && line[j:j+2] == "//" {
			break
		}
		if utils.IsLetter(line[j]) {
			// 如果是字母或者下划线开头
			j, code, name := letter(&j, line)
			addWord(i, j, code, words, name)
			continue
		}
		if utils.IsNumber(line[j]) {
			// 如果是数字开头
			j, code, name := number(&j, line)
			if code < 0 {
				my_error.Symbol_Error(i, j, words)
			}
			addWord(i, j, code, words, name)
			continue
		}
		if utils.StringsContains(BoundaryMap, line[j:j+1]) {
			// 如果是界词
			code := BoundaryMap[line[j:j+1]]
			addWord(i, j, code, words, line[j:j+1])
			continue
		}
		if utils.StringsContains(OperatorMap, line[j:j+1]) {
			// 如果是运算符
			if j+1 >= lineLen || (j+1 < lineLen && !utils.StringsContains(OperatorMap, line[j+1:j+2])) {
				// 考虑只有一个运算符，或者运算符为本行最后一个符号
				code := OperatorMap[line[j:j+1]]
				addWord(i, j, code, words, line[j:j+1])
				continue
			}
			if utils.StringsContains(OperatorMap, line[j+1:j+2]) {
				if utils.StringsContains(OperatorMap, line[j:j+2]) {
					code := OperatorMap[line[j:j+2]]
					addWord(i, j, code, words, line[j:j+2])
					j++
					continue
				}
			}
			code := OperatorMap[line[j:j+1]]
			addWord(i, j, code, words, line[j:j+1])
		}
		if line[j:j+1] == "\"" {
			// 如果是双引号
			// 从j位置遍历line，一直到下一个双引号为之
			j++
			n := j
			for ; j < lineLen; j++ {
				if line[j:j+1] == "\"" {
					// 找到下一个双引号，退出循环
					break
				}
			}
			// 添加双引号内的内容
			addWord(i, j, 600, words, line[n:j])
			continue
		}
		if line[j:j+1] == "'" {
			// 如果是单引号
			// 判断单引号后面是否只有一个字符，并且这个字符后面是否也跟着一个单引号
			if j+2 < lineLen && line[j+2:j+3] == "'" {
				addWord(i, j, 500, words, line[j+1:j+2])
				j = j + 3
				continue
			}
			my_error.Symbol_Error(i, j, words)
		}
	}
}

// 字母，判断此字母是标识符还是关键字，返回的第一个参数为i的新值，第二个参数为编码，第三个参数为单词本省
func letter(j *int, line string) (int, int, string) {
	i := *j
	defer func() {
		*j = i - 1
	}()
	lineLen := len(line)
	var temp string
	for ; i < lineLen; i++ {
		if utils.IsLetter(line[i]) {
			temp += string(line[i])
			continue
		}
		break
	}
	if utils.StringsContains(KeywordMap, temp) {
		return i, KeywordMap[temp], temp
	}
	return i, 700, temp
}

// 数字
func number(j *int, line string) (int, int, string) {
	i := *j
	// 整数为400,浮点数为800，小数为401
	state := 400
	defer func() {
		*j = i - 1
	}()
	lineLen := len(line)
	var temp string
	for ; i < lineLen; i++ {
		if utils.IsNumber(line[i]) {
			temp += string(line[i])
			continue
		}
		if line[i] == byte('.') && state == 400 {
			state = 800
			temp += string(line[i])
			continue
		}
		if line[i:i+1] == "e" || line[i:i+1] == "E" {
			state = 800
			temp += string(line[i])
			continue
		}
		if !utils.IsLetter(line[i]) {
			break
		}
		state = -2
		break
	}
	return i, state, temp
}

// 运算符

// 向words数组中添加内容
func addWord(i, j, status int, words [][]types.Word, name string) {
	var word types.Word
	word.Name = name
	word.Line = i
	word.Status = status
	word.Word = j
	words[i] = append(words[i], word)
}
